module radar_mod

  use flogger
  use obs_base_mod

  implicit none

  type, extends(obs_station_type) :: radar_station_type
    character(10) id
    real antenna_hgt
    real freq
  contains
    procedure :: init  => radar_station_init
    procedure :: print => radar_station_print
  end type radar_station_type

  type radar_moment_type
    character(10) name
    real scale_factor
    real add_offset
    real, allocatable :: bins(:)
  contains
    procedure :: init  => radar_moment_init
    procedure :: clear => radar_moment_clear
    final :: radar_moment_final
  end type radar_moment_type

  type radar_radial_type
    type(datetime_type) time
    real azimuth
    real elevation
    type(radar_moment_type), allocatable :: moments(:)
  contains
    procedure :: init  => radar_radial_init
    procedure :: clear => radar_radial_clear
    final :: radar_radial_final
  end type radar_radial_type

  type radar_scan_type
    real elevation
    real log_resolution
    real doppler_resolution
    real nyq_speed
    integer nradial
    type(radar_radial_type), allocatable :: radials(:)
  contains
    procedure :: init  => radar_scan_init
    procedure :: clear => radar_scan_clear
    final :: radar_scan_final
  end type radar_scan_type

  type, extends(obs_static_record_base_type) :: radar_record_type
    type(radar_station_type), pointer :: station => null()
    character(10) vcp ! Volume Coverage Pattern
    character(10) scan_type ! PPI, RHI
    type(radar_scan_type), allocatable :: scans(:)
  contains
    procedure :: init  => radar_record_init
    procedure :: clear => radar_record_clear
    final :: radar_record_final
  end type radar_record_type

contains

  subroutine radar_station_init(this, site_id, site_name, site_lon, site_lat, site_alt, antenna_hgt, freq)

    class(radar_station_type), intent(inout) :: this
    character(*), intent(in) :: site_id
    character(*), intent(in) :: site_name
    real, intent(in) :: site_lon
    real, intent(in) :: site_lat
    real, intent(in) :: site_alt
    real, intent(in) :: antenna_hgt
    real, intent(in) :: freq

    this%id           = site_id
    this%name         = site_name
    this%lon          = site_lon
    this%lat          = site_lat
    this%z            = site_alt
    this%antenna_hgt  = antenna_hgt
    this%freq         = freq

  end subroutine radar_station_init

  subroutine radar_station_print(this)

    class(radar_station_type), intent(in) :: this

    write(*, *) this%id
    write(*, *) 'lon: ', this%lon
    write(*, *) 'lat: ', this%lat
    write(*, *) 'z:   ', this%z
    write(*, *) 'freq:', this%freq

  end subroutine radar_station_print

  subroutine radar_moment_init(this, name, scale_factor, add_offset, nbin)

    class(radar_moment_type), intent(inout) :: this
    character(*), intent(in) :: name
    real, intent(in) :: scale_factor
    real, intent(in) :: add_offset
    integer, intent(in) :: nbin

    call this%clear()

    this%name = name
    this%scale_factor = scale_factor
    this%add_offset = add_offset
    allocate(this%bins(nbin))

  end subroutine radar_moment_init

  subroutine radar_moment_clear(this)

    class(radar_moment_type), intent(inout) :: this

    if (allocated(this%bins)) deallocate(this%bins)

  end subroutine radar_moment_clear

  subroutine radar_moment_final(this)

    type(radar_moment_type), intent(inout) :: this

    call this%clear()

  end subroutine radar_moment_final

  subroutine radar_radial_init(this, time, azimuth, elevation, nmoment)

    class(radar_radial_type), intent(inout) :: this
    type(datetime_type), intent(in) :: time
    real, intent(in) :: azimuth
    real, intent(in) :: elevation
    integer, intent(in) :: nmoment

    call this%clear()

    this%time = time
    this%azimuth = azimuth
    this%elevation = elevation
    allocate(this%moments(nmoment))

  end subroutine radar_radial_init

  subroutine radar_radial_clear(this)

    class(radar_radial_type), intent(inout) :: this

    if (allocated(this%moments)) deallocate(this%moments)

  end subroutine radar_radial_clear

  subroutine radar_radial_final(this)

    type(radar_radial_type), intent(inout) :: this

    call this%clear()

  end subroutine radar_radial_final

  subroutine radar_scan_init(this, elevation, log_resolution, doppler_resolution, nyq_speed, nradial)

    class(radar_scan_type), intent(inout) :: this
    real, intent(in) :: elevation
    real, intent(in) :: log_resolution
    real, intent(in) :: doppler_resolution
    real, intent(in) :: nyq_speed
    integer, intent(in) :: nradial

    call this%clear()

    if (doppler_resolution /= log_resolution) then
      call log_error('doppler_resolution /= log_resolution!')
    end if

    this%elevation = elevation
    this%log_resolution = log_resolution
    this%doppler_resolution = doppler_resolution
    this%nyq_speed = nyq_speed
    this%nradial = 0
    allocate(this%radials(nradial))

  end subroutine radar_scan_init

  subroutine radar_scan_clear(this)

    class(radar_scan_type), intent(inout) :: this

    if (allocated(this%radials)) deallocate(this%radials)

  end subroutine radar_scan_clear

  subroutine radar_scan_final(this)

    type(radar_scan_type), intent(inout) :: this

    call this%clear()

  end subroutine radar_scan_final

  subroutine radar_record_init(this, vcp, time, nscan)

    class(radar_record_type), intent(inout) :: this
    character(*), intent(in) :: vcp
    type(datetime_type), intent(in) :: time
    integer, intent(in) :: nscan

    call this%clear()

    this%vcp = vcp
    this%time = time
    allocate(this%scans(nscan))

  end subroutine radar_record_init

  subroutine radar_record_clear(this)

    class(radar_record_type), intent(inout) :: this

    if (allocated(this%scans)) deallocate(this%scans)

  end subroutine radar_record_clear

  subroutine radar_record_final(this)

    type(radar_record_type), intent(inout) :: this

    call this%clear()

  end subroutine radar_record_final

end module radar_mod
